import { Context, h, Schema, Session } from 'koishi'
import {} from 'koishi-plugin-adapter-onebot';

export const inject = {
    required: ["http"]
};

export const name = 'gemini-moderator'

export enum ONEBOT_IMPL_NAME {
    LAGRANGE = 1,
    NAPCAT_LLONEBOT = 2,
}

const DEFAULT_OPENAI_SYSTEM_PROMPT = `
    你是一个内容审查员。你的任务是分析用户提供的文本，并评估其有害程度。
    请返回一个 JSON 对象，其中必须包含两个字段：
    1. "score": 一个0到100之间的整数，表示文本的有害程度。0表示完全无害，100表示非常有害。
    2. "reason": 一段简短的中文说明，解释你打分的原因。
    例如: { "score": 85, "reason": "该文本包含仇恨言论。" }
    确保你的回复永远是这个格式的、不包含任何其他文字的、有效的JSON。
`;

export interface Config {
    ignoreBotSelf: boolean;
    enableGuildWhitelist: boolean;
    guildWhitelist: string[];

    useGeminiFastapiMiddleman: boolean;
    geminiMiddlemanBackendUrl: string;
    openaiBackendUrl: string;
    // openaiApiKey: string;
    openaiApiKeyList: string[];
    openaiModelName: string;
    openaiSystemPrompt: string;
    processInterval: number;

    warnScoreThreshold: number;
    showScoreAndReasonAlways: boolean;
    sendWarnCommand: boolean;
    simpleWarnCommandName: string
    onebotImplName: number;

    enableVerboseSessionOutput: boolean;
    enableVerboseConsoleOutput: boolean;
}

export const Config: Schema<Config> = Schema.intersect([
    Schema.object({
        ignoreBotSelf: Schema.boolean().default(true).description("忽略机器人自己"),
        enableGuildWhitelist: Schema.boolean().default(false).description("启用以后只会在指定的群聊生效"),
        guildWhitelist: Schema.array(Schema.string()).default([]).description("指定的群聊ID"),
    }).description("白名单配置"),

    Schema.object({
        useGeminiFastapiMiddleman: Schema.boolean().default(false).description("是否使用Gemini中间人后端。若为false，则使用下面的OpenAI兼容API配置。"),
        geminiMiddlemanBackendUrl: Schema.string().default("http://192.168.31.84:8629").description("【旧模式】Gemini中间人后端URL。格式：http(s)://ip:port"),
        openaiBackendUrl: Schema.string().default("https://api.bailili.top/v1").description("【新模式】提供OpenAI格式的AI服务的后端URL。"),
        // openaiApiKey: Schema.string().role('secret').default("sk-").description("【新模式】提供OpenAI格式的AI服务的后端给的API密钥"),
        openaiApiKeyList: Schema.array(String).role('table').default(["sk-xxx1", "sk-xxx2"]).description("【新模式】提供OpenAI格式的AI服务的后端给的API密钥"),
        openaiModelName: Schema.string().default("gemini-2.5-flash-lite").description("【新模式】提供OpenAI格式的AI服务的后端给的模型名称"),
        openaiSystemPrompt: Schema.string().default(DEFAULT_OPENAI_SYSTEM_PROMPT).role('textarea', { rows: [5, 10] }).description("【新模式】提供OpenAI格式的AI服务的后端给的系统提示"),
        processInterval: Schema.number().min(100).default(500).description("消息处理间隔，单位毫秒。用于防止请求过于频繁。"),
    }).description("AI后端配置"),

    Schema.object({
        warnScoreThreshold: Schema.number().min(0).max(100).step(1).default(80).description("警告分数阈值 (0-100)"),
        showScoreAndReasonAlways: Schema.boolean().default(false).description("总是显示分数和理由"),
        sendWarnCommand: Schema.boolean().default(true).description("发送警告命令"),
        simpleWarnCommandName: Schema.string().default("warn").description("简单警告命令名"),
        onebotImplName: Schema.union([
            Schema.const(ONEBOT_IMPL_NAME.LAGRANGE).description("Lagrange"),
            Schema.const(ONEBOT_IMPL_NAME.NAPCAT_LLONEBOT).description("Napcat或者LLOneBot"),
        ])
    }).description("警告模式配置"),

    Schema.object({
        enableVerboseSessionOutput: Schema.boolean().default(false).description("是否输出详细的会话信息"),
        enableVerboseConsoleOutput: Schema.boolean().default(false).description("是否输出详细的控制台信息"),
    }).description("debug settings")
])



export function apply(ctx: Context, config: Config) {
    const logger = ctx.logger('gemini-moderator');
    let currentApiKeyIndex = 0;

    // 创建一个用于存放待处理消息会话的队列
    const processingQueue = new Set<Session>();
    let isProcessing = false;

    // 每当收到新消息时，不再立即处理，而是将其添加到队列中
    ctx.on('message', async(session)=>{
        if ( config.ignoreBotSelf && session.userId===session.bot.selfId ) {
            return;
        }

        if ( config.enableGuildWhitelist && !config.guildWhitelist.includes(session.channelId)) {
            return;
        }

        processingQueue.add(session);
    });

    // 一个异步函数，以受控的速率处理队列中的消息
    const processQueue = async () => {
        if (isProcessing || processingQueue.size === 0) {
            return;
        }

        isProcessing = true;
        const session = processingQueue.values().next().value;
        processingQueue.delete(session);

        logger.info(`Processing message from queue. Queue size: ${processingQueue.size}`);

        try {
            const elements = h.parse(session.content);  
            let msgTextContent = "";
            for ( const e of elements ) {
                if ( e.type === "text" ) {
                    msgTextContent += e.attrs.content;
                }
            }
            
            // 如果解析后没有文本内容，则直接跳过
            if (!msgTextContent.trim()) {
                isProcessing = false;
                return;
            }

            // 定义一个变量来统一接收审查结果
            let moderationResult: { score: number; reason: string; };

            // ==================== 核心修改：根据配置选择不同的后端 ====================
            if (config.useGeminiFastapiMiddleman) {
                // 【旧逻辑】使用Gemini中间人后端
                logger.info(`Using Gemini Middleman Backend for moderation.`);
                const res = await ctx.http.post(
                    `${config.geminiMiddlemanBackendUrl}/gemini/text_moderation`, 
                    {
                        text: msgTextContent,
                    }
                );
                moderationResult = res;

            } else {
                // 【新逻辑】使用OpenAI兼容的API
                
                // ==================== 修改开始：获取循环使用的API Key ====================
                const currentApiKey = config.openaiApiKeyList[currentApiKeyIndex];
                if (!currentApiKey) {
                    logger.error('No API Key available in openaiApiKeyList.');
                    moderationResult = { score: 0, reason: "配置中没有可用的API密钥。" };
                    isProcessing = false;
                    return;
                }

                currentApiKeyIndex = (currentApiKeyIndex + 1) % config.openaiApiKeyList.length;

                logger.info(`使用OpenAI兼容的API进行文本审查。模型名称：${config.openaiModelName}。文本内容：${msgTextContent.slice(0, 60)}...。用户名称：${session.userName}。用户ID：${session.userId}。当前API Key索引：${currentApiKeyIndex}`);
                const systemPrompt = config.openaiSystemPrompt;
                
                const payload = {
                    model: config.openaiModelName,
                    messages: [
                        { role: "system", content: systemPrompt },
                        { role: "user", content: msgTextContent }
                    ],
                    temperature: 0.1, // 低温以保证输出稳定性
                    response_format: { type: "json_object" } // 开启JSON模式
                };
                
                try {
                    const response = await ctx.http.post(
                        `${config.openaiBackendUrl}/chat/completions`,
                        payload,
                        {
                            headers: {
                                'Authorization': `Bearer ${currentApiKey}`, // 使用循环的API Key
                                'Content-Type': 'application/json'
                            }
                        }
                    );

                    // OpenAI API的返回内容在 choices[0].message.content 中，且是一个JSON字符串
                    const content = response.choices[0].message.content;
                    moderationResult = JSON.parse(content);

                } catch(apiError) {
                    logger.error(`Error calling OpenAI compatible API or parsing response: ${apiError}`);
                    // 如果API调用或解析失败，设定一个无害的默认值以避免插件崩溃
                    moderationResult = { score: 0, reason: "调用AI审查接口失败或返回格式错误。" };
                }
            }
            // ========================== 核心修改结束 ==========================


            if (!moderationResult || typeof moderationResult.score === 'undefined') {
                logger.warn('Moderation result is invalid. Skipping.');
                isProcessing = false;
                return;
            }

            const isHarmful = Number(moderationResult.score) >= config.warnScoreThreshold;

            // 如果总是显示分数，或者消息被判定为有害，则发送回复
            if ( config.showScoreAndReasonAlways || isHarmful ) {
                let msgArr = [
                    `${h.quote(session.messageId)}`,
                    `${ isHarmful && config.sendWarnCommand ? `${config.simpleWarnCommandName} ${h.at(session.userId)}/.` : '' }`,
                    `有害分数: ${moderationResult.score}`,
                    `打分理由: ${moderationResult.reason}`,
                ];
                // 过滤掉空字符串的行
                await session.send(msgArr.filter(line => line).join("\n"));
            }

            if ( session.onebot && isHarmful ) {
                await setEmojiLikeOnebot(session, config);
            }
            
        } catch (e) {
            logger.error(`Error processing message: ${e}`);
        } finally {
            isProcessing = false;
        }
    };

    // 以固定的时间间隔运行消息处理函数
    ctx.setInterval(processQueue, config.processInterval);

    async function setEmojiLikeOnebot(session: Session, config: Config){
        ctx.logger.info(`Onebot贴表情.`);
        try {
            if ( Number(config.onebotImplName) === ONEBOT_IMPL_NAME.LAGRANGE ){
                await session.onebot._request(
                    "set_group_reaction",
                    {
                        "group_id": session.guildId,
                        "message_id": session.messageId,
                        "code": "123",
                        "is_add": true,
                    }
                );
            } else if ( Number(config.onebotImplName) === ONEBOT_IMPL_NAME.NAPCAT_LLONEBOT ){
                // 注意：不同OneBot实现的API和参数可能有差异
                await session.onebot._request(
                    "set_msg_emoji_like",
                    {
                        "message_id": session.messageId,
                        "emoji_id": 123,
                        "set": true,
                    }
                );
            }
        } catch (e) {
            logger.warn(`Failed to set emoji reaction: ${e.message}`);
        }
    }
}